﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using System.IO;
using Microsoft.DirectX;

namespace ParticleEditor
{
    public partial class EditorForm : Form
    {
        SGP.CSGP_Direct3D DX = SGP.CSGP_Direct3D.GetInstance();
        SGP.CSGP_TextureManager TM = SGP.CSGP_TextureManager.GetInstance();

        // public variables
        #region
        // BOOL
        public bool loop = true; // editorForm loop

        // FLOAT
        public float elapsedTime; // SEE STOPWATCH

        // STOPWATCH
        public Stopwatch stopWatch = new Stopwatch(); // stopWatch function

        // currently active emitter
        public Emitter activeEmitter;
        #endregion

        // default ctor
        public EditorForm()
        {
            InitializeComponent();

            DX.Initialize(renderPanel, false);
            DX.AddRenderTarget(renderPanel);
            TM.Initialize(DX.Device, DX.Sprite);

            activeEmitter = new Emitter();

            // pre-set location of particle details box (appearance only)
            particleDetailsBox.Location = new Point(12, 165);
        }

        // display the particles
        public void Render()
        {
            activeEmitter.Render(renderPanel);
        }

        // update the program
        public new void Update()
        {
            // calculate the elasped time between frames
            stopWatch.Stop();
            elapsedTime = (float)stopWatch.Elapsed.TotalSeconds;
            stopWatch.Reset();
            stopWatch.Start();

            // switch emitType
            switch (activeEmitter.emitType)
            {
                case 0:
                    PointEmitter.Checked = true;
                    break;
                case 1:
                    RectangleEmitter.Checked = true;
                    break;
                case 2:
                    CircleEmitter.Checked = true;
                    break;
                case 3:
                    LineEmitter.Checked = true;
                    break;
            }

            isLoopingCheckBox.Checked = activeEmitter.isLooping ? true : false;
            // update the emitter
            if (activeEmitter != null)
                activeEmitter.Update(elapsedTime);

            // update NUDs and Sliders
            UpdateFormInfo();
        }

        // update NUDs and Sliders
        public void UpdateFormInfo()
        {
            // update NUDs
            spawnRateNUD.Value = (decimal)activeEmitter.spawnRate;
            circleRadiusNUD.Value = (decimal)activeEmitter.circleVector.Y;
            lineLengthNUD.Value = (decimal)activeEmitter.lineVector.Y;
            numParticlesNUD.Value = (decimal)activeEmitter.maxNumParticles;
            rectSizeXNUD.Value = (decimal)activeEmitter.emitterRectSize.Width;
            rectSizeYNUD.Value = (decimal)activeEmitter.emitterRectSize.Height;
            maxAgeSeconds.Value = (decimal)activeEmitter.maxParticleAge;
            startVelocityXNUD.Value = (decimal)activeEmitter.startVelocity.X;
            startVelocityYNUD.Value = (decimal)activeEmitter.startVelocity.Y;
            startRotationNUD.Value = (decimal)activeEmitter.startRotation;
            endRotationNUD.Value = (decimal)activeEmitter.endRotation;
            endVelocityXNUD.Value = (decimal)activeEmitter.endVelocity.X;
            endVelocityYNUD.Value = (decimal)activeEmitter.endVelocity.Y;
            startScaleXNUD.Value = (decimal)activeEmitter.startScale.X;
            startScaleYNUD.Value = (decimal)activeEmitter.startScale.Y;
            endScaleXNUD.Value = (decimal)activeEmitter.endScale.X;
            endScaleYNUD.Value = (decimal)activeEmitter.endScale.Y;
            startAlphaNUD.Value = (decimal)activeEmitter.startColor.A;
            endAlphaNUD.Value = (decimal)activeEmitter.endColor.A;

            // update Sliders
            spawnRateSlider.Value = (int)activeEmitter.spawnRate;
            circleRadiusSlider.Value = (int)activeEmitter.circleVector.Y;
            lineLengthSlider.Value = (int)activeEmitter.lineVector.Y;
            particleCountSlider.Value = (int)activeEmitter.maxNumParticles;
            sizeXSlider.Value = (int)activeEmitter.emitterRectSize.Width;
            sizeYSlider.Value = (int)activeEmitter.emitterRectSize.Height;
            maxAgeSlider.Value = (int)activeEmitter.maxParticleAge;
            startRotationSlider.Value = (int)activeEmitter.startRotation;
            endRotationSlider.Value = (int)activeEmitter.endRotation;
            startVelocityXSlider.Value = (int)activeEmitter.startVelocity.X;
            startVelocityYSlider.Value = (int)activeEmitter.startVelocity.Y;
            endVelocityXSlider.Value = (int)activeEmitter.endVelocity.X;
            endVelocityYSlider.Value = (int)activeEmitter.endVelocity.Y;
            startScaleXSlider.Value = (int)activeEmitter.startScale.X;
            startScaleYSlider.Value = (int)activeEmitter.startScale.Y;
            endScaleXSlider.Value = (int)activeEmitter.endScale.X;
            endScaleYSlider.Value = (int)activeEmitter.endScale.Y;
        }

        // form interactions
        #region
        // end the program
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            loop = false;
        }

        // point emitter radial button
        private void PointEmitter_MouseClick(object sender, MouseEventArgs e)
        {
            lineEmitterBox.Visible = false;
            circleEmitterBox.Visible = false;
            circleEmitterBox.Location = new Point(135, 165);
            rectangleEmitterBox.Visible = false;
            particleDetailsBox.Location = new Point(12, 165);

            activeEmitter.emitType = 0;
        }

        // rectangle emitter radial button
        private void RectangleEmitter_MouseClick(object sender, MouseEventArgs e)
        {
            lineEmitterBox.Visible = false;
            circleEmitterBox.Visible = false;
            circleEmitterBox.Location = new Point(135, 165);
            rectangleEmitterBox.Visible = true;
            particleDetailsBox.Location = new Point(12, 240);

            activeEmitter.emitType = 1;

        }

        // circle emitter radial button
        private void CircleEmitter_MouseClick(object sender, MouseEventArgs e)
        {
            lineEmitterBox.Visible = false;
            circleEmitterBox.Visible = true;
            circleEmitterBox.Location = new Point(6, 88);
            rectangleEmitterBox.Visible = false;
            particleDetailsBox.Location = new Point(12, 195);

            activeEmitter.emitType = 2;

        }

        // line emitter radial button
        private void LineEmitter_MouseClick(object sender, MouseEventArgs e)
        {
            lineEmitterBox.Visible = true;
            circleEmitterBox.Visible = false;
            circleEmitterBox.Location = new Point(135, 165);
            rectangleEmitterBox.Visible = false;
            particleDetailsBox.Location = new Point(12, 195);

            activeEmitter.emitType = 3;

        }

        // emitter looping checkbox
        private void isLooping_CheckStateChanged(object sender, EventArgs e)
        {
            activeEmitter.isLooping = isLoopingCheckBox.Checked ? true : false;
        }

        // number of particles
        private void numParticlesNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(particleCountSlider))
                activeEmitter.maxNumParticles = (int)particleCountSlider.Value;
            else
                activeEmitter.maxNumParticles = (int)numParticlesNUD.Value;
        }

        // length of the line emitter
        private void lineLengthNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(lineLengthSlider))
                activeEmitter.lineVector.Y = (float)lineLengthSlider.Value;
            else
                activeEmitter.lineVector.Y = (float)lineLengthNUD.Value;
        }

        // particle spawn rate
        private void spawnRateNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(spawnRateSlider))
                activeEmitter.spawnRate = (float)spawnRateSlider.Value;
            else
                activeEmitter.spawnRate = (float)spawnRateNUD.Value;
        }

        // X-value for the rectangle emitter
        private void rectSizeXNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(sizeXSlider))
                activeEmitter.emitterRectSize.Width = (int)sizeXSlider.Value;
            else
                activeEmitter.emitterRectSize.Width = (int)rectSizeXNUD.Value;
        }

        // Y-value for the rectangle emitter
        private void rectSizeYNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(sizeYSlider))
                activeEmitter.emitterRectSize.Height = (int)sizeYSlider.Value;
            else
                activeEmitter.emitterRectSize.Height = (int)rectSizeYNUD.Value;
        }

        // maximum particle age (in seconds)
        private void maxAgeSeconds_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(maxAgeSlider))
                activeEmitter.maxParticleAge = (float)maxAgeSlider.Value;
            else
                activeEmitter.maxParticleAge = (float)maxAgeSeconds.Value;
        }

        // radius for circle emitter
        private void circleRadiusNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(circleRadiusSlider))
                activeEmitter.circleVector.Y = (float)circleRadiusSlider.Value;
            else
                activeEmitter.circleVector.Y = (float)circleRadiusNUD.Value;

        }

        // change the font color in the 'file' menu when opened
        private void fileToolStripMenuItem_DropDownOpened(object sender, EventArgs e)
        {
            fileToolStripMenuItem.ForeColor = Color.Black;
        }

        // change the font color in the 'file' menu when closed
        private void fileToolStripMenuItem_DropDownClosed(object sender, EventArgs e)
        {
            fileToolStripMenuItem.ForeColor = Color.Wheat;
        }

        // change the font color of the 'file' menu when the mouse hovers over
        private void fileToolStripMenuItem_MouseHover(object sender, EventArgs e)
        {
            fileToolStripMenuItem.ForeColor = Color.Black;
        }

        // change the font color of the 'file' menu when the mouse leaves
        private void fileToolStripMenuItem_MouseLeave(object sender, EventArgs e)
        {
            fileToolStripMenuItem.ForeColor = Color.Wheat;
        }

        // move the emitter using the mouse
        private void renderPanel_MouseClick(object sender, MouseEventArgs e)
        {
            activeEmitter.moveDirectionX1 = e.Location.X > activeEmitter.position.X ? -1 : 1;
            activeEmitter.moveDirectionY1 = e.Location.Y > activeEmitter.position.Y ? -1 : 1;

            activeEmitter.position = new Vector2(e.Location.X, e.Location.Y);
        }

        // click and drag the emitter using the mouse
        private void renderPanel_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
                renderPanel_MouseClick(sender, e);
        }

        // starting velocity X-value
        private void startVelocityXNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(startVelocityXSlider))
                activeEmitter.startVelocity.X = (float)startVelocityXSlider.Value;
            else
                activeEmitter.startVelocity.X = (float)startVelocityXNUD.Value;
        }

        // starting velocity Y-value
        private void startVelocityYNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(startVelocityYSlider))
                activeEmitter.startVelocity.Y = (float)startVelocityYSlider.Value;
            else
                activeEmitter.startVelocity.Y = (float)startVelocityYNUD.Value;
        }

        // ending velocity X-value
        private void endVelocityXNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(endVelocityXSlider))
                activeEmitter.endVelocity.X = (float)endVelocityXSlider.Value;
            else
                activeEmitter.endVelocity.X = (float)endVelocityXNUD.Value;
        }

        // ending velocity Y-value
        private void endVelocityYNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(endVelocityYSlider))
                activeEmitter.endVelocity.Y = (float)endVelocityYSlider.Value;
            else
                activeEmitter.endVelocity.Y = (float)endVelocityYNUD.Value;
        }

        // starting scale X-value
        private void startScaleXNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(startScaleXSlider))
                activeEmitter.startScale.X = (float)startScaleXSlider.Value;
            else
                activeEmitter.startScale.X = (float)startScaleXNUD.Value;
        }

        // starting scale Y-value
        private void startScaleYNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(startScaleYSlider))
                activeEmitter.startScale.Y = (float)startScaleYSlider.Value;
            else
                activeEmitter.startScale.Y = (float)startScaleYNUD.Value;
        }

        // ending scale X-value
        private void endScaleXNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(endScaleXSlider))
                activeEmitter.endScale.X = (float)endScaleXSlider.Value;
            else
                activeEmitter.endScale.X = (float)endScaleXNUD.Value;
        }

        // ending scale Y-value
        private void endScaleYNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(endScaleYSlider))
                activeEmitter.endScale.Y = (float)endScaleYSlider.Value;
            else
                activeEmitter.endScale.Y = (float)endScaleYNUD.Value;
        }

        // starting color values
        private void startColorNUD_ValueChanged(object sender, EventArgs e)
        {
            int tempA = (int)activeEmitter.startColor.A;
            int tempR = (int)activeEmitter.startColor.R;
            int tempG = (int)activeEmitter.startColor.G;
            int tempB = (int)activeEmitter.startColor.B;

            if (sender.Equals(startAlphaNUD))
                tempA = (int)startAlphaNUD.Value;

            // updated current startColor
            activeEmitter.startColor = Color.FromArgb(tempA, tempR, tempG, tempB);
        }

        // ending color values
        private void endColorNUD_ValueChanged(object sender, EventArgs e)
        {
            int tempA = (int)activeEmitter.endColor.A;
            int tempR = (int)activeEmitter.endColor.R;
            int tempG = (int)activeEmitter.endColor.G;
            int tempB = (int)activeEmitter.endColor.B;

            if (sender.Equals(endAlphaNUD))
                tempA = (int)endAlphaNUD.Value;

            activeEmitter.endColor = Color.FromArgb(tempA, tempR, tempG, tempB);
        }

        // starting rotation values
        private void startRotationNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(startRotationSlider))
                activeEmitter.startRotation = (float)startRotationSlider.Value;
            else
                activeEmitter.startRotation = (float)startRotationNUD.Value;
        }

        // ending rotation values
        private void endRotationNUD_ValueChanged(object sender, EventArgs e)
        {
            if (sender.Equals(endRotationSlider))
                activeEmitter.endRotation = (float)endRotationSlider.Value;
            else
                activeEmitter.endRotation = (float)endRotationNUD.Value;
        }

        // save to XML
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            activeEmitter.SaveToXML();
        }

        // open from XML
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            activeEmitter = activeEmitter.LoadFromXML();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void changeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "All Files|*.*|Bmp Files|*.bmp|Jpg|*.jpg|Png|*.png";
            dlg.FilterIndex = 1;

            dlg.InitialDirectory = System.IO.Path.GetFullPath(System.IO.Directory.GetCurrentDirectory() + "\\..\\..\\resource\\Graphics");

            if (DialogResult.OK == dlg.ShowDialog())
            {
                // load new imageID
                activeEmitter.imageID = TM.LoadTexture(dlg.FileName);
                activeEmitter.particleImage = new Bitmap(dlg.FileName);
                // record image path
                string currLoc = dlg.FileName;

                activeEmitter.imageName = dlg.SafeFileName;
                // reduce image path to imageName only
                activeEmitter.imageName = activeEmitter.imageName.Substring(activeEmitter.imageName.LastIndexOf('\\') + 1);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ColorDialog MyDialog = new ColorDialog();
            // Keeps the user from selecting a custom color.
            MyDialog.AllowFullOpen = false;
            // Allows the user to get help. (The default is false.)
            MyDialog.ShowHelp = true;
            // Sets the initial color select to the current text color.
            MyDialog.Color = button1.ForeColor;

            // Update the text box color if the user clicks OK  
            if (MyDialog.ShowDialog() == DialogResult.OK)
            {
                int r = MyDialog.Color.R;
                int g = MyDialog.Color.G;
                int b = MyDialog.Color.B;

                activeEmitter.startColor = Color.FromArgb(activeEmitter.startColor.A, r, g, b);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ColorDialog MyDialog = new ColorDialog();
            // Keeps the user from selecting a custom color.
            MyDialog.AllowFullOpen = false;
            // Allows the user to get help. (The default is false.)
            MyDialog.ShowHelp = true;
            // Sets the initial color select to the current text color.
            MyDialog.Color = button1.ForeColor;

            // Update the text box color if the user clicks OK  
            if (MyDialog.ShowDialog() == DialogResult.OK)
            {
                int r = MyDialog.Color.R;
                int g = MyDialog.Color.G;
                int b = MyDialog.Color.B;

                activeEmitter.endColor = Color.FromArgb(activeEmitter.endColor.A, r, g, b);
            }
        }
        #endregion

    }
}
